﻿// CMyInjectionDlg.cpp: 实现文件
//

#include "pch.h"
#include "HackSkill.h"
#include "CMyInjectionDlg.h"
#include "afxdialogex.h"
#include <tlhelp32.h>
#include<algorithm>
// CMyInjectionDlg 对话框

IMPLEMENT_DYNAMIC(CMyInjectionDlg, CDialogEx)

CMyInjectionDlg::CMyInjectionDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_DIALOG_RemoteThreadInjection, pParent)
	, csDllPath(_T(""))
{

}

CMyInjectionDlg::~CMyInjectionDlg()
{

}

void CMyInjectionDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_MFCEDITBROWSE1, csDllPath);
	DDX_Control(pDX, IDC_LIST1, m_ListCtrl);
}


BEGIN_MESSAGE_MAP(CMyInjectionDlg, CDialogEx)
	ON_WM_DROPFILES()
    ON_NOTIFY(NM_RCLICK, IDC_LIST1, &CMyInjectionDlg::OnNMRClickList1)
END_MESSAGE_MAP()


// CMyInjectionDlg 消息处理程序


BOOL CMyInjectionDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	//解决以管理员运行，接收不到DropFile
	ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
	ChangeWindowMessageFilter(0x0049, MSGFLT_ADD); // 0x0049 == WM_COPYGLOBALDATA

	// TODO:  在此添加额外的初始化
	m_ListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
	m_ListCtrl.InsertColumn(1, L"进程名称", LVCFMT_LEFT, 200, 1);
	m_ListCtrl.InsertColumn(2, L"PID", LVCFMT_CENTER, 80, 1);
	m_ListCtrl.InsertColumn(3, L"线程数量", LVCFMT_CENTER, 80, 1);
	m_ListCtrl.InsertColumn(4, L"进程路径", LVCFMT_LEFT, 450, 1);
	RefreshProcess();
	return TRUE;  // return TRUE unless you set the focus to a control
				  // 异常: OCX 属性页应返回 FALSE
}


void CMyInjectionDlg::OnDropFiles(HDROP hDropInfo)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	UINT count = 0;
	
	csDllPath = _T("");

	//从成功的拖放操作中检索文件的名称，获取拖拽文件的数目
	count = DragQueryFile(hDropInfo, 0xFFFFFFFF, NULL, 0);

	//如果只拖拽一个文件夹
	if (count == 1)
	{
		//获得拖拽的文件名
		DragQueryFile(hDropInfo, 0, filePath, sizeof(filePath));

		//保存文件路径
		csDllPath = filePath;

		//显示文件路径
		CWnd* pWnd = GetDlgItem(IDC_MFCEDITBROWSE1);
		pWnd->SetWindowText(filePath);
	}
	else if (count > 1)
	{
		MessageBox(_T("不支持多个文件！"), _T("提示"));
	}

	CDialogEx::OnDropFiles(hDropInfo);
}


//自定义sortb比较
bool SortCmp(const PROCESSINFO& a, const PROCESSINFO& b) 
{
	if (a.szExeFile[0] == '[')
	{
		return a.szExeFile[0] < b.szExeFile[0];
	}
	else if (b.szExeFile[0] == '[')
	{
		return a.szExeFile[0] < b.szExeFile[0];
	}
	else 
	{
		return a.szExeFile[0] > b.szExeFile[0];
	}
}


//刷新进程信息
void CMyInjectionDlg::RefreshProcess()
{
	//清空列表
	m_ListCtrl.DeleteAllItems();

	//清空容器
	vecProcessInfo.clear();

	//保存快照信息
	PROCESSENTRY32 process_info = { sizeof(PROCESSENTRY32) };

	//进程快照
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

	//遍历快照
	if (Process32First(snapshot, &process_info))
	{
		do {
			HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, process_info.th32ProcessID);

			// 定义保存进程信息的结构体
			PROCESSINFO m_ProcessInfo = { 0 };
			DWORD length = MAX_PATH*2;
		
			//查询并输出路径
			QueryFullProcessImageNameW(process, 0, m_ProcessInfo.path, &length);
			//转换进程ID
			swprintf_s(m_ProcessInfo.szPid, 15, L"%u", process_info.th32ProcessID);
			//转换线程数量
			swprintf_s(m_ProcessInfo.countThread, 15, L"%u", process_info.cntThreads);
			//保存进程名称
			memcpy_s(m_ProcessInfo.szExeFile, MAX_PATH, process_info.szExeFile, MAX_PATH);

			//插入向量
			vecProcessInfo.push_back(m_ProcessInfo);

			//关闭句柄
			CloseHandle(process);

		} while (Process32Next(snapshot, &process_info));
	}
	//关闭句柄
	CloseHandle(snapshot);

	//遍历容器设置list
	ListVector_SetList();

	//更新数据到控件
	UpdateData(FALSE);

	return;
}


//遍历容器设置list
void CMyInjectionDlg::ListVector_SetList() 
{
	sort(vecProcessInfo.begin(), vecProcessInfo.end(), SortCmp);
	for (auto iter = vecProcessInfo.cbegin(); iter != vecProcessInfo.cend(); iter++)
	{	
		//打印进程信息
		m_ListCtrl.InsertItem(0, iter->szExeFile);        //进程名称
		m_ListCtrl.SetItemText(0, 1, iter->szPid);        //进程ID
		m_ListCtrl.SetItemText(0, 2, iter->countThread);  //线程数量
		m_ListCtrl.SetItemText(0, 3, iter->path);         //进程路径
	}
}



void CMyInjectionDlg::OnNMRClickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(TRUE);

	//CString to char
	USES_CONVERSION;
	char* path = T2A(csDllPath.GetBuffer(0));
	csDllPath.ReleaseBuffer();

	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
	int index = pNMLV->iItem;
	if (index == -1)
		return;
	HMENU hMenu = ::CreatePopupMenu();
	AppendMenu(hMenu, MF_STRING, 10000, _T("打开进程所在路径"));
	AppendMenu(hMenu, MF_STRING, 10001, _T("使用远程线程注入"));
	AppendMenu(hMenu, MF_STRING, 10002, _T("突破SESSION 0隔离注入"));
	AppendMenu(hMenu, MF_STRING, 10003, _T("使用APC方式注入"));
	AppendMenu(hMenu, MF_STRING, 10004, _T("刷新进程列表"));
	AppendMenu(hMenu, MF_STRING, 10005, _T("结束选中进程"));
	AppendMenu(hMenu, MF_STRING, 10006, _T("取消"));
	CPoint pt;
	GetCursorPos(&pt); //获得当前鼠标位置
	UINT Cmd = (UINT)::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, m_hWnd, NULL);//弹出菜单

	//保存进程PID
	CString csPID = m_ListCtrl.GetItemText(index, 1);//第2列为进程PID，获取其信息
	DWORD dwPID = _ttoi(csPID);

	//保存进程路径
	CString csDir= m_ListCtrl.GetItemText(index, 3);//第4列为进程路径，获取其信息

	//响应点击的菜单
	switch (Cmd)
	{
	case 10000:
		//打开进程所在路径
		OpenFilePathFolder(csDir);
		break;

	case 10001:
		if (csDllPath == L"")
		{
			MessageBox(_T("没有拖拽文件！"), _T("提示"));
			*pResult = 0;
			return;
		}
		//判断是否Dll
		if (IsDllFile(ReadFileToMemory(path)))
		{
			//远程线程注入
			CreateRemoteThreadInjection(dwPID, path);
		}
		break;

	case 10002:
		if (csDllPath == L"")
		{
			MessageBox(_T("没有拖拽文件！"), _T("提示"));
			*pResult = 0;
			return;
		}
		//判断是否Dll
		if (IsDllFile(ReadFileToMemory(path)))
		{
			//突破SESSION 0注入
			Session0Injection(dwPID, path);
		}
		break;

	case 10003:
		if (csDllPath == L"")
		{
			MessageBox(_T("没有拖拽文件！"), _T("提示"));
			*pResult = 0;
			return;
		}
		//判断是否Dll
		if (IsDllFile(ReadFileToMemory(path)))
		{
			//APC注入
			InjectByApc(dwPID, path);
		}
		break;

	case 10004:
		//刷新进程
		RefreshProcess();
		break;

	case 10005:
		MessageBox(_T("确定结束选中进程？"), _T("提示"),MB_YESNO);
		//结束进程
		TerminateProcessID(dwPID);
		Sleep(1000);
		//刷新进程
		RefreshProcess();
		break;

	case 10006:

		break;
	}
	*pResult = 0;
}


//结束进程
void CMyInjectionDlg::TerminateProcessID(DWORD processID)
{
	//获取进程句柄
	HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, processID);

	//结束进程
	TerminateProcess(hProcess, 0);

	//关闭句柄
	CloseHandle(hProcess);

	return;
}


//打开指定路径的文件夹
void CMyInjectionDlg::OpenFilePathFolder(CString csDir) 
{
	WIN32_FIND_DATAW FindFileData;
	FindFirstFile(csDir, &FindFileData);
	//FindFirstFileA(tempPath,&FindFileData);
	if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
	{
		//Folder
		//打开文件夹
		ShellExecute(NULL, L"open", NULL, NULL, csDir, SW_SHOWNORMAL);
	}
	else
	{
		//File
		int dotPos = csDir.ReverseFind('\\');
		//获取文件扩展名
		CString filePath = csDir.Left(dotPos);
		ShellExecute(NULL, L"open", NULL, NULL, filePath, SW_SHOWNORMAL);
	}
}


//读取文件到内存
char* CMyInjectionDlg::ReadFileToMemory(char* pFilePath)
{
	//打开文件获取句柄
	HANDLE hFile = CreateFileA(pFilePath, GENERIC_READ, FALSE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		MessageBox(_T("文件打开失败！"), _T("提示"));
		return NULL;
	}

	//获取文件大小
	DWORD dwFileSize = GetFileSize(hFile, NULL);

	//申请内存
	char* pBuff = new char[dwFileSize]();

	//读文件
	DWORD dwRead;
	ReadFile(hFile, pBuff, dwFileSize, &dwRead, NULL);

	//关闭文件
	CloseHandle(hFile);

	//返回内存指针
	return pBuff;
}


//判断是否Dll文件
BOOL CMyInjectionDlg::IsDllFile(char* pFileBuff)
{
	//Dos头结构体指针=文件起始位置
	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFileBuff;

	//判断Dos头结构体成员变量e_magic
	if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
	{
		MessageBox(_T("不是PE文件！"), _T("提示"));
		if (pFileBuff != NULL)
		{
			delete[] pFileBuff;
		}
		return FALSE;
	}

	//NT头结构体指针=起始位置+偏移
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pFileBuff + pDos->e_lfanew);

	//判断NT头成员变量Signature
	if (pNt->Signature != IMAGE_NT_SIGNATURE)
	{
		MessageBox(_T("不是PE文件！"), _T("提示"));
		if (pFileBuff != NULL)
		{
			delete[] pFileBuff;
		}
		return FALSE;
	}

	//判断是不是Dll
	if (!((pNt->FileHeader.Characteristics & IMAGE_FILE_DLL) == IMAGE_FILE_DLL))
	{
		MessageBox(_T("不是DLL文件！"), _T("提示"));
		if (pFileBuff != NULL)
		{
			delete[] pFileBuff;
		}
		return FALSE;
	}
	if (pFileBuff != NULL)
	{
		delete[] pFileBuff;
	}
	return TRUE;
}


//远程线程注入
BOOL CMyInjectionDlg::CreateRemoteThreadInjection(DWORD dwPID,char* pDllPath)
{
	//打开进程获取句柄
	HANDLE hProcess = NULL;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);

	//check
	if (hProcess == NULL)
	{
		return FALSE;
	}

	//在远程进程中申请内存
	LPVOID pDllAddr = NULL;
	pDllAddr = VirtualAllocEx(hProcess,NULL,strlen(pDllPath)+1,MEM_COMMIT,PAGE_READWRITE);

	//check
	if (pDllAddr == NULL)
	{
		return FALSE;
	}

	//在远程内存中写入DLL路径
	if (FALSE == WriteProcessMemory(hProcess, pDllAddr, pDllPath, strlen(pDllPath) + 1, NULL))
	{
		return FALSE;
	}

	//获取LoadLibrary函数地址
	FARPROC pLoadLibrary = NULL;
	pLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"),"LoadLibraryA");

	//check
	if (pLoadLibrary == NULL)
	{
		return FALSE;
	}

	//创建远程线程，实现DLL注入
	HANDLE hRemoteThread = NULL;
	hRemoteThread =CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pDllAddr, 0, NULL);

	//check
	if (hRemoteThread == NULL)
	{
		return FALSE;
	}

	
	//等待线程结束
	WaitForSingleObject(hRemoteThread, INFINITE);

	//释放内存
	VirtualFreeEx(hProcess, pDllAddr, MAX_PATH, MEM_RESERVE);

	//关闭句柄
	CloseHandle(hRemoteThread);
	CloseHandle(hProcess);

	return TRUE;
}


//突破SESSION 0注入
BOOL CMyInjectionDlg::Session0Injection(DWORD dwPID, char* pDllPath)
{
	//打开进程获取句柄
	HANDLE hProcess = NULL;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);

	//check
	if (hProcess == NULL)
	{
		return FALSE;
	}

	//在远程进程中申请内存
	LPVOID pDllAddr = NULL;
	pDllAddr = VirtualAllocEx(hProcess, NULL, strlen(pDllPath) + 1, MEM_COMMIT, PAGE_READWRITE);

	//check
	if (pDllAddr == NULL)
	{
		return FALSE;
	}

	//在远程内存中写入DLL路径
	if (FALSE == WriteProcessMemory(hProcess, pDllAddr, pDllPath, strlen(pDllPath) + 1, NULL))
	{
		return FALSE;
	}

	//获取LoadLibrary函数地址
	FARPROC pLoadLibrary = NULL;
	pLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");

	//check
	if (pLoadLibrary == NULL)
	{
		return FALSE;
	}

	//加载ntdll获取ZwCreateThreadEx函数地址
	HMODULE hNtDll = LoadLibraryA("ntdll.dll");

	//获取ZwCreateThreadEx函数地址
	ZwCreateThreadEx = (fnZwCreateThreadEx)GetProcAddress(hNtDll, "ZwCreateThreadEx");

	//check
	if (ZwCreateThreadEx == NULL)
	{
		return FALSE;
	}

	//创建远程线程，实现DLL注入
	HANDLE hRemoteThread = NULL;
	ZwCreateThreadEx(&hRemoteThread,
		             PROCESS_ALL_ACCESS, 
		             NULL, 
		             hProcess,
		             (LPTHREAD_START_ROUTINE)pLoadLibrary,
		             pDllAddr, 
		             0,0 ,0,0,
		             NULL);

	//check
	if (hRemoteThread == NULL)
	{
		return FALSE;
	}

	//等待线程结束
	WaitForSingleObject(hRemoteThread, INFINITE);

	//释放内存
	VirtualFreeEx(hProcess, pDllAddr, MAX_PATH, MEM_RESERVE);

	//关闭句柄
	CloseHandle(hRemoteThread);
	CloseHandle(hProcess);


	return TRUE;
}



//获取线程信息
BOOL CMyInjectionDlg::GetThreadIdByProcessId(DWORD Pid, vector<DWORD> &vecThreadId)
{
	// 创建一个线程快照, 参数二写任何数值，最终遍历到的都是所有线程
	HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);

	// 创建一个结构体用于保存线程的信息
	THREADENTRY32 ThreadInfo = { sizeof(THREADENTRY32) };

	// 清空向量
	vecThreadId.clear();

	// 尝试从快照中获取到第一个线程
	if (Thread32First(Snapshot, &ThreadInfo))
	{
		// 对遍历到的数据进行输出
		do {
			// 如果遍历到的线程父进程为PID就进行输出
			if (ThreadInfo.th32OwnerProcessID == Pid)
			{
				// 保存ThreadId到向量
				vecThreadId.push_back(ThreadInfo.th32ThreadID);
		
			}// 尝试获取下一个线程的信息
		} while (Thread32Next(Snapshot, &ThreadInfo));
	}
	// 关闭句柄
	CloseHandle(Snapshot);

	//check容器
	if (vecThreadId.empty())
	{
		return FALSE;
	}
	else
	{
		return TRUE;
	}
}


//APC注入
BOOL CMyInjectionDlg::InjectByApc(DWORD dwPID, char* pDllPath)
{
	//打开进程获取句柄
	HANDLE hProcess = NULL;
	hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);

	//check
	if (hProcess == NULL)
	{
		return FALSE;
	}

	//在远程进程中申请内存
	LPVOID pDllAddr = NULL;
	pDllAddr = VirtualAllocEx(hProcess, NULL, strlen(pDllPath) + 1, MEM_COMMIT, PAGE_READWRITE);

	//check
	if (pDllAddr == NULL)
	{
		return FALSE;
	}

	//在远程内存中写入DLL路径
	if (FALSE == WriteProcessMemory(hProcess, pDllAddr, pDllPath, strlen(pDllPath) + 1, NULL))
	{
		return FALSE;
	}

	//获取LoadLibrary函数地址
	FARPROC pLoadLibrary = NULL;
	pLoadLibrary = GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");

	//check
	if (pLoadLibrary == NULL)
	{
		return FALSE;
	}

	//获取当前进程所有的线程ID
	GetThreadIdByProcessId(dwPID, vecThreadId);

	//遍历线程，插入APC
	for (auto iter = vecThreadId.cbegin(); iter != vecThreadId.cend(); iter++)
	{
		//打开线程
		HANDLE hThread = NULL;
		hThread =OpenThread(THREAD_ALL_ACCESS, FALSE, *iter);

		//check句柄
		if (hThread)
		{
			//插入APC
			QueueUserAPC((PAPCFUNC)pLoadLibrary,hThread, (ULONG_PTR)pDllAddr);
			//关闭句柄
			CloseHandle(hThread);
		}
	}

	return TRUE;
}